package com.bjpowernode.mvc.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.bjpowernode.common.client.RedisClient;
import com.bjpowernode.common.constant.AppConstants;
import com.bjpowernode.common.constant.RedisKey;
import com.bjpowernode.common.enums.RespCode;
import com.bjpowernode.common.pay.PayUtil;
import com.bjpowernode.db.domain.AccountDetail;
import com.bjpowernode.db.domain.Recharge;
import com.bjpowernode.db.mapper.AccountDetailMapper;
import com.bjpowernode.db.mapper.RechargeMapper;
import com.bjpowernode.db.mapper.SysAccountMapper;
import com.bjpowernode.mvc.model.dto.KqBeginDTO;
import com.bjpowernode.mvc.service.inter.PayService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Set;

@RequiredArgsConstructor
@Service
public class PayServiceImpl implements PayService {

    private final RedisClient redisClient;
    private final RechargeMapper rechargeMapper;
    private final SysAccountMapper sysAccountMapper;
    private final AccountDetailMapper accountDetailMapper;

    /**
     * 提供通过网银支付接口所需要的参数
     *
     * @param uid
     * @param token
     * @param phone
     * @param payMoney
     * @return
     */
    @Override
    public KqBeginDTO generateApiParam(Integer uid, String token, String phone, BigDecimal payMoney) {
        //生成订单号：时间戳 + 唯一序号(redis incr命令  将key中储存的数字增一)
        String orderId = "KQ" + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()) + redisClient.incr(RedisKey.PAY_ORDER_SEQ);
        KqBeginDTO kqBeginDTO = new KqBeginDTO(uid, token, phone, payMoney, orderId);
        return kqBeginDTO;
    }

    /**
     * 创建充值记录
     *
     * @param uid
     * @param orderId
     * @param payMoney
     * @param channel
     */
    @Override
    public void createRechargeRecord(Integer uid, String orderId, BigDecimal payMoney, String channel) {
        Recharge recharge = new Recharge();
        //用户id
        recharge.setUid(uid);
        //充值订单号
        recharge.setRechargeNo(orderId);
        //充值订单状态（0充值中，1充值成功，2充值失败）
        recharge.setRechargeStatus(AppConstants.STA_RECHARGE_PROCESSING);
        //充值金额
        recharge.setRechargeMoney(payMoney);
        //充值时间
        recharge.setRechargeTime(new Date());
        //充值描述
        recharge.setRechargeDesc("快钱充值");
        //充值渠道
        recharge.setChannel(channel);

        rechargeMapper.insert(recharge);
    }

    /**
     * 保存订单号到Redis
     *
     * @param orderId
     */
    @Override
    public void saveOrderIdRedis(String orderId) {
        redisClient.addZSet(RedisKey.PAY_ORDER_SET, orderId, new Date().getTime());
    }

    /**
     * 验证uid和token是否正确
     *
     * @param uid   sessionStorage中
     * @param token
     * @return
     */
    @Override
    public boolean checkUidToken(Integer uid, String token) {
        String key = RedisKey.TOKEN_ACCESS + token.toUpperCase();
        if (redisClient.exists(key)) {
            String saveUid = redisClient.getHashField(key, "uid");
            String headerUid = String.valueOf(uid);
            return StrUtil.isNotBlank(headerUid) && (headerUid.equals(saveUid));
        }
        return false;
    }

    /**
     * 处理订单
     *
     * @param orderId   商户订单号
     * @param payAmount 订单金额
     * @param payResult 支付结果
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String handleNotify(String orderId, String payAmount, String payResult) {
        //1、查询订单
        Recharge recharge = rechargeMapper.selectByOrderIdForUpdate(orderId);
        if (recharge == null) {
            //无充值记录
            return RespCode.RECHARGE_RECODE_NULL.name();
        }

        //2、判断订单的状态
        if (recharge.getRechargeStatus() > AppConstants.STA_RECHARGE_PROCESSING) {
            //该订单已被处理过
            return RespCode.RECHARGE_HANDLE_DOUBLE.name();
        }

        //3、判断订单金额
        String payFen = recharge.getRechargeMoney().multiply(new BigDecimal("100")).stripTrailingZeros().toPlainString();
        if (!payFen.equals(payAmount)) {
            return RespCode.RECHARGE_MONEY_DIFF.name();
        }

        //4、判断充值结果
        int result = 0;
        //充值记录Wrapper
        UpdateWrapper<Recharge> updateWrapper = new UpdateWrapper<>();
        if ("10".equals(payResult)) {
            //4.1更新充值余额
            result = sysAccountMapper.updateAvailableMoneyByRecharge(recharge.getUid(), recharge.getRechargeMoney());
            if (result < 1) {
                throw new RuntimeException("充值，更新账号余额失败！");
            }
            //4.2记录账号流水
            AccountDetail accountDetail = new AccountDetail();
            accountDetail.setUid(recharge.getUid());
            //对账号的操作 ：add增加金额， sub:减少金额
            accountDetail.setAction(AppConstants.OPERATION_ADD);
            //时间
            accountDetail.setActionTime(new Date());
            //操作金额
            accountDetail.setMoney(recharge.getRechargeMoney());
            //备注
            accountDetail.setMemo("充值金额：" + recharge.getRechargeMoney());
            accountDetailMapper.insert(accountDetail);


            //4.3更新充值记录状态
            updateWrapper.eq("id", recharge.getId());
            updateWrapper.set("recharge_status", AppConstants.STA_RECHARGE_SUCC);
            result = rechargeMapper.update(null, updateWrapper);
            if (result < 1) {
                throw new RuntimeException("充值，更新记录状态失败！");
            }
        } else {
            //充值失败
            updateWrapper.eq("id", recharge.getId());
            updateWrapper.set("recharge_status", AppConstants.STA_RECHARGE_FAIL);
            result = rechargeMapper.update(null, updateWrapper);
            if (result < 1) {
                throw new RuntimeException("充值，更新记录状态失败！");
            }
        }
        return RespCode.OK.name();
    }

    /**
     * 删除redis中的已经处理订单号
     *
     * @param orderId
     */
    @Override
    public void deleteOrderId(String orderId) {
        redisClient.deleteValue(RedisKey.PAY_ORDER_SET, orderId);
    }

    /**
     * 获取未处理的订单号的集合
     *
     * @return
     */
    @Override
    public Set<ZSetOperations.TypedTuple<String>> getUntreatedOrderId() {
        //取所有数据
        return redisClient.getRange(RedisKey.PAY_ORDER_SET, 0, -1);
    }

    /**
     * 对订单进行订单结果的查询
     *
     * @param orderId
     * @return
     */
    @Override
    public String executeQueryOrderId(String orderId) {
        return PayUtil.queryOrderId(orderId);
    }

    /**
     * 订单查询结果失败，为空，没有查询结果,支付失败
     *
     * @param orderId
     * @param status
     */
    @Override
    public void modifyRechargeStatus(String orderId, int status) {
        UpdateWrapper<Recharge> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("recharge_no", orderId);
        updateWrapper.set("recharge_status", status);
        //更新订单查询结果为失败
        rechargeMapper.update(null, updateWrapper);
    }


}
